typedef enum logic [1:0] {
    IDLE = 2'b00,
    RECV = 2'b01,
    EXEC = 2'b10,
    DONE = 2'b11
} state_t;

module Processor (
    input   logic clock,
    input   logic rst_n,
    input   logic valid,
    output  logic busy,
    output  logic done
);
    state_t curr_state, next_state;

    always_ff @(posedge clock or negedge rst_n) begin
        if (!rst_n) begin
            curr_state <= IDLE;
        end 
        else begin
            curr_state <= next_state;
        end
    end

    always_comb begin
        next_state = curr_state;
        case (curr_state)
            IDLE: begin
                next_state = valid ? RECV : IDLE;
            end
            RECV: begin
                next_state = EXEC;
            end
            EXEC: begin
                next_state = DONE;
            end
            DONE: begin
                next_state = IDLE;
            end
            default: begin
                next_state = IDLE;
            end
        endcase
    end

    assign busy = curr_state != IDLE;
    assign done = curr_state == DONE;

endmodule

module coverage_fsm;

    logic clock;
    logic rst_n;
    logic valid;
    logic busy;
    logic done;

    Processor dut(
        .clock (clock),
        .rst_n (rst_n),
        .valid (valid),
        .busy  (busy),
        .done  (done)
    );

    // 时钟生成
    initial begin
        clock = 0;
        forever #5 clock = ~clock;
    end
    
    covergroup StateTransitionCov @(posedge clock);

        cp_state: coverpoint dut.curr_state {
            
            // 值分箱: 确保每个状态都被达到过
            bins idle = {IDLE};
            bins recv = {RECV};
            bins exec = {EXEC};
            bins done = {DONE};

            // 转移分箱: 检查状态跳转
            // 语法: (state1 => state2, state3) 表示从 state1 到 state2 或 state3 的跳转
            bins idle_to_recv = (IDLE => RECV);
            bins recv_to_exec = (RECV => EXEC);
            bins exec_to_done = (EXEC => DONE);
            bins done_to_idle = (DONE => IDLE);
            
            // 检查在某个状态的停留
            bins idle_stay = (IDLE => IDLE);
        }
    endgroup

    // 实例化 covergroup
    StateTransitionCov cov_inst = new;

    initial begin
        rst_n = 0;
        valid = 0;
        repeat(2) @(negedge clock);

        rst_n = 1;
        valid = 1;

        repeat(6) @(negedge clock);
        
        $finish;
    end

endmodule
